#ifndef AIOBJECTMANAGER
#define AIOBJECTMANAGER

#if _MSC_VER > 1000
#pragma once
#endif



#include "IAIObjectManager.h"
#include "IEntityPoolManager.h"

#include "PoolAllocator.h"

typedef std::multimap<short, CCountedRef<CAIObject> > AIObjectOwners;
typedef std::multimap<short, CWeakRef<CAIObject> > AIObjects;

enum EAIClass
{
	eAIC_Invalid,

	eAIC_FIRST,

	eAIC_AIObject = eAIC_FIRST,
	eAIC_AIActor,
	eAIC_AIPlayer,
	eAIC_PipeUser,
	eAIC_Puppet,
	eAIC_AIVehicle,

	eAIC_LAST = eAIC_AIVehicle
};

struct SAIObjectCreationHelper
{
	SAIObjectCreationHelper(CAIObject* pObject);
	void Serialize(TSerialize ser);
	CAIObject* RecreateObject(void* alloc = NULL);

	string name;
	EAIClass aiClass;
	tAIObjectID objectId;
};


class CAIObjectManager : public IAIObjectManager, public IEntityPoolListener
{
public:

	CAIObjectManager();
	virtual ~CAIObjectManager();

	void Init();
	void Reset(bool includingPooled = true);
	void PostSerialize();

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//IAIObjectManager/////////////////////////////////////////////////////////////////////////////////////////////

	VIRTUAL IAIObject *CreateAIObject(const AIObjectParams& params);
	VIRTUAL void RemoveObject(tAIObjectID objectID);

	VIRTUAL IAIObject *GetAIObject(tAIObjectID aiObjectID);
	VIRTUAL IAIObject *GetAIObjectByName(unsigned short type, const char *pName) const;

	// Returns AIObject iterator for first match, see EGetFirstFilter for the filter options.
	// The parameter 'n' specifies the type, group id or species based on the selected filter.
	// It is possible to iterate over all objects by setting the filter to OBJFILTER_TYPE
	// passing zero to 'n'.
	VIRTUAL IAIObjectIter* GetFirstAIObject(EGetFirstFilter filter, short n);
	// Iterates over AI objects within specified range.
	// Parameter 'pos' and 'rad' specify the enclosing sphere, for other parameters see GetFirstAIObject.
	VIRTUAL IAIObjectIter* GetFirstAIObjectInRange(EGetFirstFilter filter, short n, const Vec3& pos, float rad, bool check2D);

	//IAIObjectManager/////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//IEntityPoolListener//////////////////////////////////////////////////////////////////////////////////////////
	virtual void OnEntityPreparedFromPool(EntityId entityId, IEntity *pEntity);
	virtual void OnEntityReturnedToPool(EntityId entityId, IEntity *pEntity);
	virtual void OnPoolDefinitionsLoaded(size_t numAI);
	virtual void OnBookmarkEntitySerialize(TSerialize serialize, void *pVEntity);
		//IEntityPoolListener//////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// callback from CObjectContainer: notify the rest of the system that the object is disappearing
	void OnObjectRemoved(CAIObject *pObject);

	//// it removes all references to this object from all objects of the specified type
	//// (MATT) Note that is does not imply deletion - vehicles use it when they lose their driver {2009/02/05}
	void RemoveObjectFromAllOfType(int nType, CAIObject* pRemovedObject);

	void CreateDummyObject(CCountedRef<CAIObject>& ref, const char* name="", CAIObject::ESubType type = CAIObject::STP_NONE, tAIObjectID requiredID = INVALID_AIOBJECTID);
	void CreateDummyObject(CStrongRef <CAIObject>& ref, const char* name="", CAIObject::ESubType type = CAIObject::STP_NONE, tAIObjectID requiredID = INVALID_AIOBJECTID);

	CAIObject * GetAIObjectByName(const char *pName) const;

	void ReleasePooledObject(CAIObject* pObject);
	bool IsSerializingBookmark() const { return m_serializingBookmark; }

	// todo: ideally not public
	AIObjectOwners m_Objects;// m_RootObjects or EntityObjects might be better names
	AIObjectsSet m_mapDummyObjects;

protected:

	typedef std::map<EntityId, CCountedRef<CAIObject> > TPooledAIObjectMap;
	TPooledAIObjectMap m_pooledObjects;
	
	typedef class CAIVehicle TPooledAIObject;	// Currently CAIVehicle is the largest class; ensures there is always space in the pool
	stl::TPoolAllocator<TPooledAIObject> * m_pPoolAllocator;

	// set to true during the process of serializing an AI object to/from an entity pool bookmark. This allows
	//	objects owned by the current object to be serialized into the bookmark as well.
	bool m_serializingBookmark;

	size_t m_PoolBucketSize;
};

#endif
